/*
题目: 课程表
你这个学期必须选修 numCourses 门课程，记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出，其中 prerequisites[i] = [ai, bi] ，表示如果要学习课程 ai 则 必须 先学习课程  bi 。

    例如，先修课程对 [0, 1] 表示：想要学习课程 0 ，你需要先完成课程 1 。

请你判断是否可能完成所有课程的学习？如果可以，返回 true ；否则，返回 false 。

https://leetcode.cn/problems/course-schedule/description/
 */
public class CanFinish {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        // 拓扑排序
        int[] indegree = new int[numCourses]; // 入度
        int n = prerequisites.length;

        for (int[] cur : prerequisites) {
            indegree[cur[1]] ++; // 入度 ++
        }

        int vertex = findZeroDegree(indegree);
        int count = 0;
        while (vertex != -1) {
            indegree[vertex] = -1; // 标记为 已访问
            count ++; //  入度为 0 的结点 数量 +1

            for (int[] cur : prerequisites) {
                if (cur[0] == vertex) {
                    indegree[cur[1]] --;
                }
            }

            vertex = findZeroDegree(indegree);
        }

        return count == numCourses;
    }

    // 寻找入度为 0 的点, 不存在则返回 -1
    public int findZeroDegree(int[] indegree) {
        for (int i = 0; i < indegree.length; i ++) {
            if (indegree[i] == 0) {
                return i;
            }
        }
        return -1;
    }
}
